import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class ScopeCheck {
	Stack<BGDLTreeNode> stack;
	Stack<BGDLTreeNode> stackvarinit;
	BGDLTreeNode root;
	BGDLTreeNode currentNode;
	BGDLTreeNode initcurrentNode;
	ArrayList<String> rep= new ArrayList<String>();
	ArrayList<String> all= new ArrayList<String>();
	ArrayList<String> varinit= new ArrayList<String>();
	
	
	public  ScopeCheck(BGDLTreeNode root){
		if (root.equals(null))
			System.out.println("error: root is null");
		else{
			this.root = root;
			}
				
		}
	
	public String checking(){
		
		stack = new Stack<BGDLTreeNode>();
		stack.push(root);		
				while(!stack.empty()){
					currentNode=stack.pop();
					all.add(currentNode.value);
					for (int i=currentNode.children.size()-1;i>=0;i--)
					{	
						BGDLTreeNode Children = currentNode.children.get(i);
						if (currentNode.children.get(i)!=null)
						{
							stack.push(Children);
						}
					}				
				}		
//				printArraylist(all);
//				String key=checkKey(all);
//				System.out.println(key);
				
//				if (key.isEmpty())
//				{
//					System.out.println("no need to check");
//				}
				if (all.contains("function"))
				{
					int progCount=0;
					ArrayList<Integer> progIndex= new ArrayList<Integer>();
					for (int j=0;j<all.size();j++)
					{
						if (all.get(j).equals("function"))
						{
							progCount++;
							progIndex.add(j);
						}
					}
//					System.out.println(progIndex.size());
					if (progCount==1)
					{
						if (checkBlock(all)==true)
						{
							return "";
							//this is good
						}
						else
						{
							//this is bad
							return "Scope error.\n Warning: no BoardGame.java output file";
						}
					}
					else if (progCount==2)
					{
						int t =  Integer.parseInt(progIndex.get(1).toString());
						List<String> proglist1=all.subList(0,t);
						List<String> proglist2=all.subList(t,all.size());
						if (checkBlock(proglist1)==true&&checkBlock(proglist2)==true)
						{
							return "";
							//this is good
						}
						else
						{
							//this is bad
							return "Scope error.\n Warning: no BoardGame.java output file";
						}
						
					}
					else if (progCount==3)
					{
						int t = Integer.parseInt(progIndex.get(1).toString());
						int tnext = Integer.parseInt(progIndex.get(2).toString());
						int end = all.size();
						List<String> proglist0 =all.subList(0,t);
						List<String> proglist1 =all.subList(t,tnext);
						List<String> proglist2 =all.subList(tnext, end);
						
						if (checkBlock(proglist0)==true&&checkBlock(proglist1)==true&&checkBlock(proglist2)==true)
						{
							return "";
							//this is good
						}
						else
						{
							//this is bad
							return "Scope error.\n Warning: no BoardGame.java output file";
						}
					}
					else if (progCount==4)
					{
						int t = Integer.parseInt(progIndex.get(1).toString());
						int tnext = Integer.parseInt(progIndex.get(2).toString());
						int tnextnext =Integer.parseInt(progIndex.get(3).toString());
						int end = all.size();
						List<String> proglist0 =all.subList(0,t);
						List<String> proglist1 =all.subList(t,tnext);
						List<String> proglist2 =all.subList(tnext, tnextnext);
						List<String> proglist3 =all.subList(tnextnext,end);
						
						if (checkBlock(proglist0)==true&&checkBlock(proglist1)==true&&checkBlock(proglist2)==true&&checkBlock(proglist3))
						{
							return "";
							//this is good
						}
						else
						{
							//this is bad
							return "Scope error.\n Warning: no BoardGame.java output file";
						}
					}
						
				}
		return "";
	}
	
	private List<String> checkKey(ArrayList<String> checkList)//Check which variable need to be checked
	{
		String key = "";
		List<String> keyList=new ArrayList<String>();
		for (int m=0;m<checkList.size();m++)
		{
			if (checkList.indexOf(checkList.get(m))!=m && checkList.contains(checkList.get(m)))
			{
				if (!checkList.get(m).equals("int")&&!checkList.get(m).equals("empty")
						&&!checkList.get(m).equals("INT_LITERAL")
						&&!checkList.get(m).equals("stmt_list")
						&&!checkList.get(m).equals("var_init")
						&&!checkList.get(m).equals("=")
						&&!checkList.get(m).equals("block")
						&&!checkList.get(m).equals("STRING_LITERAL")
						&&!checkList.get(m).equals("String"))
				{
//					System.out.println("Need to scope Check:\n"+checkList.get(m));
					key = (String)checkList.get(m);
				}
			}
			if (!keyList.contains(key)&&!key.equals(""))
				keyList.add(key);
			
		}
		return keyList;
	}
	
	private boolean initialCheck(List<String> initialCheck)//Check if initialized
	{
		
		if ((initialCheck.contains("var_init")&&initialCheck.contains("=")&&initialCheck.contains("INT_LITERAL")))
			return true;
		else
			return false;
	}
	
	private boolean initialCheckString(List<String> initialCheck)
	{
		if ((initialCheck.contains("var_init")&&initialCheck.contains("=")&&initialCheck.contains("STRING_LITERAL")))
			return true;
		else
			return false;
	}
	private boolean initialCheckDouble(List<String> initialCheck)
	{
		if ((initialCheck.contains("var_init")&&initialCheck.contains("=")&&initialCheck.contains("DOUBLE_LITERAL")))
			return true;
		else
			return false;
	}
	
	private boolean initialCheckBoolean(List<String> initialCheck)
	{
		if ((initialCheck.contains("var_init")&&initialCheck.contains("=")&&initialCheck.contains("BOOLEAN_LITERAL")))
			return true;
		else
			return false;
	}

	
	private void printArraylist(List<String> list)// Printout ArrayList
	{
		for (int i=0;i<list.size();i++)
		{
			System.out.print(list.get(i)+" ");
		}
		System.out.println();
	}
	
	private Boolean checkBlock(List<String> checkBlocklist)
	{
		int blockCount=0;
		ArrayList<Integer> index= new ArrayList<Integer>();
//		String k= checkKey(all);
		List<String> keyList=checkKey(all);
//		System.out.println("this is damn:"+ k);
		for (int i=0;i<checkBlocklist.size();i++)
		{
			if (checkBlocklist.get(i).equals("block"))
			{
				blockCount++;
				index.add(i);
			}
		}
		for (int m=0;m<keyList.size();m++)
		{
		if (blockCount==1)
		{	
			if (!keyList.isEmpty())
			{
			
				if (all.get(all.indexOf(keyList.get(m))-1).equals("int"))
				{
					if (!initialCheck(all))
					{
//						System.out.println("Need to initialize integers");
						return false;
					}
					else if (all.get(all.lastIndexOf(keyList.get(m))-1).equals("int"))
					{
//						System.out.println("Can't initialize twice");
						return false;
					}
					
					}	
				if (all.get(all.indexOf(keyList.get(m))-1).equals("String"))
				{
					if (!initialCheckString(all))
					{
//						System.out.println("Need to initialize Strings");
						return false;
					}
					else if (all.get(all.lastIndexOf(keyList.get(m))-1).equals("String"))
					{
//						System.out.println("Can't initialize twice");
						return false;
					}
				}
				if (all.get(all.indexOf(keyList.get(m))-1).equals("double"))
				{
					if (!initialCheckDouble(all))
					{
//						System.out.println("Need to initialize Doubles");
						return false;
					}
					else if (all.get(all.lastIndexOf(keyList.get(m))-1).equals("double"))
					{
//						System.out.println("Can't initialize twice");
						return false;
					}
				}
					
				if (all.get(all.indexOf(keyList.get(m))-1).equals("boolean"))
				{
					if (!initialCheckBoolean(all))
					{
//						System.out.println("Need to initialize Booleans");
						return false;
					}
					else if (all.get(all.lastIndexOf(keyList.get(m))-1).equals("boolean"))
					{
//						System.out.println("Can't initialize twice");
						return false;
					}
				}
			}
				
		}
		if (blockCount==2)
		{
			int x = Integer.parseInt(index.get(0).toString());
			int xnext = Integer.parseInt(index.get(1).toString());
			int end = checkBlocklist.size();
			
			List<String> templist1 =checkBlocklist.subList(x,xnext);
			List<String> templist2 =checkBlocklist.subList(xnext, end);
//			printArraylist(templist1);
		
			
			if (!keyList.isEmpty())
			{
				if (all.get(all.indexOf(keyList.get(m))-1).equals("int"))
				{	
					if (!initialCheck(all))
					{
//						System.out.println("Need to initialize integers");
						return false;
					}
					
					else if (initialCheck(templist1)&&templist1.contains(keyList.get(m))&&(!initialCheck(templist2)))
					{
						int intCount=0;
						for (int i=0; i<templist1.size();i++)
						{
							if (templist1.get(i).equals("int"))
							{
								intCount++;
								
							}
						}
						if (intCount>1)
						{
							if (templist1.get(templist1.indexOf("int")+1).equals(keyList.get(m))&&templist1.get(templist1.lastIndexOf("int")+1).equals(keyList.get(m)))
							{
								return false;
							}
						}
						
					}
					
					else if (initialCheck(templist1)&&templist1.contains(keyList.get(m))&&initialCheck(templist2)&&templist2.contains(keyList.get(m)))
					{
//						System.out.println("Can't initialize twice DUDE!!!");
						return false;
					}
				}
				
				if (all.get(all.indexOf(keyList.get(m))-1).equals("String"))
				{	
					if (!initialCheckString(all))
					{
//						System.out.println("Need to initialize Strings");
						return false;
					}
					
					else if (initialCheckString(templist1)&&templist1.contains(keyList.get(m))&&(!initialCheckString(templist2)))
					{
						int stringCount=0;
						for (int i=0; i<templist1.size();i++)
						{
							if (templist1.get(i).equals("String"))
							{
								stringCount++;
								
							}
						}
						if (stringCount>1)
						{
							if (templist1.get(templist1.indexOf("String")+1).equals(keyList.get(m))&&templist1.get(templist1.lastIndexOf("String")+1).equals(keyList.get(m)))
							{
								return false;
							}
						}
						
					}
					else if (initialCheckString(templist1)&&templist1.contains(keyList.get(m))&&initialCheckString(templist2)&&templist2.contains(keyList.get(m)))
					{
//						System.out.println("Can't initialize twice DUDE!!!");
						return false;
					}
				}
				
				if (all.get(all.indexOf(keyList.get(m))-1).equals("double"))
				{	
					if (!initialCheckDouble(all))
					{
//						System.out.println("Need to initialize Doubles");
						return false;
					}

					else if (initialCheckDouble(templist1)&&templist1.contains(keyList.get(m))&&(!initialCheckDouble(templist2)))
					{
						int doubleCount=0;
						for (int i=0; i<templist1.size();i++)
						{
							if (templist1.get(i).equals("double"))
							{
								doubleCount++;
								
							}
						}
						if (doubleCount>1)
						{
							if (templist1.get(templist1.indexOf("double")+1).equals(keyList.get(m))&&templist1.get(templist1.lastIndexOf("double")+1).equals(keyList.get(m)))
							{
								return false;
							}
						}
						
					}
					
					
					else if (initialCheckDouble(templist1)&&templist1.contains(keyList.get(m))&&initialCheckDouble(templist2)&&templist2.contains(keyList.get(m)))
					{
//						System.out.println("Can't initialize twice DUDE!!!");
						return false;
					}
				}
				
				if (all.get(all.indexOf(keyList.get(m))-1).equals("boolean"))
				{	
					if (!initialCheckBoolean(all))
					{
//						System.out.println("Need to initialize Booleans");
						return false;
					}

					
					else if (initialCheckBoolean(templist1)&&templist1.contains(keyList.get(m))&&(!initialCheckBoolean(templist2)))
					{
						int booleanCount=0;
						for (int i=0; i<templist1.size();i++)
						{
							if (templist1.get(i).equals("boolean"))
							{
								booleanCount++;
								
							}
						}
						if (booleanCount>1)
						{
							if (templist1.get(templist1.indexOf("boolean")+1).equals(keyList.get(m))&&templist1.get(templist1.lastIndexOf("boolean")+1).equals(keyList.get(m)))
							{
								return false;
							}
						}
						
					}	
					else if (initialCheckBoolean(templist1)&&templist1.contains(keyList.get(m))&&initialCheckBoolean(templist2)&&templist2.contains(keyList.get(m)))
					{
//						System.out.println("Can't initialize twice DUDE!!!");
						return false;
					}
				}
					
			}
		}
		
		else if (blockCount==3)
		{			
			
			int x = Integer.parseInt(index.get(0).toString());
			int xnext = Integer.parseInt(index.get(1).toString());	
			int xnextnext = Integer.parseInt(index.get(2).toString());
			int end = checkBlocklist.size();
			
			List<String> templist1 =checkBlocklist.subList(x,xnext);
			List<String> templist2 =checkBlocklist.subList(xnext, xnextnext);
			List<String> templist3 =checkBlocklist.subList(xnextnext, end);
			
			if (!keyList.isEmpty())
			{
				if (!initialCheck(all))
				{
//					System.out.println("Need to initialize interger!");
					return false;
				}
				
				else if ((initialCheck(templist1)&&templist1.contains(keyList.get(m))&&initialCheck(templist2)&&templist2.contains(keyList.get(m)))
						||(initialCheck(templist1)&&templist1.contains(keyList.get(m))&&initialCheck(templist3)&&templist3.contains(keyList.get(m)))
						||(initialCheck(templist2)&&templist2.contains(keyList.get(m))&&initialCheck(templist3)&&templist3.contains(keyList.get(m))))
				{
//					System.out.println("Can't initialize twice DUDE!!!");
					return false;
				}
				
			}
		}	
		}
		
		return true;
		
	}

}
